home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia 1995 April / Informatica Multimedia CD - Epimundo.iso / DOS / FILEFIND / LOCATE.ZIP / LOCATE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-04  |  46.6 KB  |  1,425 lines

  1. static char *description[] = {            
  2.  "┌───────────────────────────────────────────────────────────────────────┐",
  3.  "│         LOCATE by Terry E. Crandall, 1993.    Version 1.0             │",
  4.  "│                                                                       │",
  5.  "│   LOCATE is FreeWare.  If you find it useful, or have any comments,   │",
  6.  "│   send me a note to either Compuserve [76620,521], or 1101 Lake Heron │",
  7.  "│   Drive, #1C, Annapolis, Maryland, 21403.  I would love to hear from  │",
  8.  "│   you.                                                                │",
  9.  "├───────────────────────────────────────────────────────────────────────┤",
  10.  "│Usage:              LOCATE [options] [filespec]                        │",
  11.  "│                                                                       │",
  12.  "│  ∙  OPTIONS are specified with a slash (/), followed by a symbol,     │",
  13.  "│     and optionally followed by arguments pertaining to the option.    │",
  14.  "│                                                                       │",
  15.  "│  ∙  Multiple options MUST be separated by white space, i.e.,          │",
  16.  "│     '/R/ES' implies '/ES' is an argument of '/R'.  Correct is         │",
  17.  "│     '/R /ES'.                                                         │",
  18.  "│                                                                       │",
  19.  "│  ∙  If arguments contain spaces or any symbols that have special      │",
  20.  "│     meaning to MSDOS, e.g., '<' or '|', then the argument (or the     │",
  21.  "│     switch and its argument) must be enclosed within quotes.          │",
  22.  "│                                                                       │",
  23.  "│     For example,        /F<<<< $f >>>>          will not work         │",
  24.  "│                         /F\042<<<< $f >>>>\042        will work             │",
  25.  "│                         \042/F<<<< $f >>>>\042        will also work        │",
  26.  "│                                                                       │",
  27.  "│  ∙  Quotes (\042) may be included inside an argument by prefixing them   │",
  28.  "│     by a backslash: \\\042                                                │",
  29.  "│                                                                       │",
  30.  "│  ∙  FILESPEC defaults to *.* if not given.  Do not include a drive    │",
  31.  "│     specification...LOCATE only works on the current drive, or        │",
  32.  "│     multiple drives (see /M switch).                                  │",
  33.  "├───────────────────────────────────────────────────────────────────────┤",
  34.  "│NOTATION USED IN ARGUMENTS COLUMN:                                     │",
  35.  "│                                                                       │",
  36.  "│  ∙  the ¿ symbol indicates that the argument is one of several        │",
  37.  "│     choices that cannot be used with each other, i.e., only one       │",
  38.  "│     of the arguments can be present.                                  │",
  39.  "│                                                                       │",
  40.  "│  ∙  the  symbol indicates that the argument is the default argument  │",
  41.  "│     if its switch is given without any arguments.                     │",
  42.  "│                                                                       │",
  43.  "│                                                                       │",
  44.  "│Opt      Arguments                 Description and Examples            │",
  45.  "├─────────────────────┬─────────────────────────────────────────────────┤",
  46.  "│/?   [/switch...]    │ Display some or all of help                     │",
  47.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  48.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  49.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  50.  "│                     │ ∙  /?                       display entire help │",
  51.  "│                     │ ∙  /? /F /S     display help for /F and /S only │",
  52.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  53.  "│/A   attribute[-]... │ Locate only files with specified attribute, or  │",
  54.  "│                     │ [-] without specified attribute.                │",
  55.  "│                     │   See also /E and /V switches.                 │",
  56.  "│                     ├─────────────────────────────────────────────────┤",
  57.  "│         R           │ Read-only                                       │",
  58.  "│         H           │ Hidden                                          │",
  59.  "│         S           │ System                                          │",
  60.  "│         L           │ Label                                           │",
  61.  "│         D           │ Directory                                       │",
  62.  "│         A           │ Archive                                         │",
  63.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  64.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  65.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  66.  "│                     │ ∙  /AH                 choose only hidden files │",
  67.  "│                     │ ∙  /AHD-L   choose hidden, exclude directories, │",
  68.  "│                     │                               and choose labels │",
  69.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  70.  "│/A   [mmddyy] [hhmm] │ Locate only files dated AFTER date or date/time │",
  71.  "│                     │   See also /B and /D switches. 7                │",
  72.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  73.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  74.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  75.  "│                     │ ∙  /A060191 1720     after 5:20pm, June 1, 1991 │",
  76.  "│                     │ ∙  /A0900                       after 9am TODAY │",
  77.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  78.  "│/B   [mmddyy] [hhmm] │ Locate only files dated BEFORE date or date/time│",
  79.  "│                     │   See also /A and /D switches.                 │",
  80.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  81.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  82.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  83.  "│                     │ ∙  /B112787          before November 27th, 1987 │",
  84.  "│                     │ ∙  /A010190 /B010191         only files in 1990 │",
  85.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  86.  "│/C   # columns       │ Split listing into '#' columns.                 │",
  87.  "│                     │   See also /I and /L switches.                 │",
  88.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  89.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  90.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  91.  "│                     │ ∙  /C2                      display two columns │",
  92.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  93.  "│/D   # days          │ Locate only files dated within number of days   │",
  94.  "│                     │   See also /A and /B switches.                 │",
  95.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  96.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  97.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  98.  "│                     │ ∙  /D2              files dated since yesterday │",
  99.  "│                     │ ∙  /D            files dated today; same as /D1 │",
  100.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  101.  "│/E    option         │ Exclude from Recursive Search.                  │",
  102.  "│                     ├─────────────────────────────────────────────────┤",
  103.  "│         C          │ Exclude current working directory               │",
  104.  "│         R           │ Exclude ROOT directory                          │",
  105.  "│         S           │ Exclude subdirectories of ROOT                  │",
  106.  "│                     ├─────────────────────────────────────────────────┤",
  107.  "│                     │ The difference between /ES and /AD- is that no  │",
  108.  "│                     │ <files> inside directories will be processed for│",
  109.  "│                     │ sub-directories with /ES, but only descendants  │",
  110.  "│                     │ that are sub-directory <FILES> in the chain are │",
  111.  "│                     │ processed for /AD-.                             │",
  112.  "│                     ├─────────────────────────────────────────────────┤",
  113.  "│                     │ $d     Day of file          (mon, tue, .., sun) │",
  114.  "│                     │ #d     Day of file             (01, 02, .., 31) │",
  115.  "│                     │ $e     Extension of file                  (■■■) │",
  116.  "│                     │ $f     Name of file              (■■■■■■■■.■■■) │",
  117.  "│                     │ #f     abbrev for $p\\$f         (see $p and $f) │",
  118.  "│                     │ $k     Size of file in kilobytes       (■■■■■K) │",
  119.  "│                     │ #k     ALLOCATED size of file          (■■■■■K) │",
  120.  "│                     │ $m     Month of file        (jan, feb, .., dec) │",
  121.  "│                     │ #m     Month of file           (01, 02, .., 12) │",
  122.  "│                     │ $p     Disk and path of directory   (■:\\path..) │",
  123.  "│                     │        If '\\' directory, then              (■:) │",
  124.  "│                     │ #p     Path of directory             (\\path..) │",
  125.  "│                     │ $s     Size of file in bytes        (■■■■■■■■■) │",
  126.  "│                     │ #s     ALLOCATED size of file       (■■■■■■■■■) │",
  127.  "│                     │ $t     Time of file                  (HH:MM:SS) │",
  128.  "│                     │ #t     Time of file                     (HH:MM) │",
  129.  "│                     │ #u     Upper (PARENT) directory      (■■■■■■■■) │",
  130.  "│                     │ $y     Year of file      (1980, 1981, .., 1999) │",
  131.  "│                     │ #y     Year of file            (80, 81, .., 99) │",
  132.  "│                     │ $=n    Skip to column 'n', e.g., $=30 or $=100  │",
  133.  "│                     │ $$     The symbol $                             │",
  134.  "│                     │ $#     The symbol #                             │",
  135.  "│                     ├─────────────────────────────────────────────────┤",
  136.  "│                     │   See also /A, /R and /V switches.             │",
  137.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  138.  "│/F   format-string   │ Specifies format of listing line for each file  │",
  139.  "│                     │   The listed output pertaining to each file is │",
  140.  "│                     │    the text in 'format-string', with the tokens │",
  141.  "│                     │    below being replaced by the value(s) for the │",
  142.  "│                     │    file                                         │",
  143.  "│                     │   See also /X switch.                          │",
  144.  "│                     ├─────────────────────────────────────────────────┤",
  145.  "│                     │ $a     Attributes of file              (RHSVDA) │",
  146.  "│                     │ #a     Attributes of file                (0x■■) │",
  147.  "│                     │ $b     Basename of file              (■■■■■■■■) │",
  148.  "│                     │ $c     Size, in MSDOS clusters         (■■■■■■) │",
  149.  "│                     │ $d     Day of file          (mon, tue, .., sun) │",
  150.  "│                     │ #d     Day of file             (01, 02, .., 31) │",
  151.  "│                     │ $e     Extension of file                  (■■■) │",
  152.  "│                     │ $f     Name of file              (■■■■■■■■.■■■) │",
  153.  "│                     │ #f     abbrev for $p\\$f         (see $p and $f) │",
  154.  "│                     │ $k     Size of file in kilobytes       (■■■■■K) │",
  155.  "│                     │ #k     ALLOCATED size of file          (■■■■■K) │",
  156.  "│                     │ $m     Month of file        (jan, feb, .., dec) │",
  157.  "│                     │ #m     Month of file           (01, 02, .., 12) │",
  158.  "│                     │ $p     Disk and path of directory   (■:\\path..) │",
  159.  "│                     │        If '\\' directory, then              (■:) │",
  160.  "│                     │ #p     Path of directory             (\\path..) │",
  161.  "│                     │ $s     Size of file in bytes        (■■■■■■■■■) │",
  162.  "│                     │ #s     ALLOCATED size of file       (■■■■■■■■■) │",
  163.  "│                     │ $t     Time of file                  (HH:MM:SS) │",
  164.  "│                     │ #t     Time of file                     (HH:MM) │",
  165.  "│                     │ #u     Upper (PARENT) directory      (■■■■■■■■) │",
  166.  "│                     │ $y     Year of file      (1980, 1981, .., 1999) │",
  167.  "│                     │ #y     Year of file            (80, 81, .., 99) │",
  168.  "│                     │ $=n    Skip to column 'n', e.g., $=30 or $=100  │",
  169.  "│                     │ $$     The symbol $                             │",
  170.  "│                     │ $#     The symbol #                             │",
  171.  "│                     ├─────────────────────────────────────────────────┤",
  172.  "│                     │   Token replacements are in all lowercase or   │",
  173.  "│                     │    all uppercase if the token is in lowercase   │",
  174.  "│                     │    or upper case, respectively.                 │",
  175.  "│                     │   All size tokens are replaced with '<DIR>'    │",
  176.  "│                     │    if directory entry is a subdirectory.        │",
  177.  "│                     │   Attribute tokens ($a, #a) are replaced by    │",
  178.  "│                     │    text: (R)ead-only (H)idden (S)ystem, (L)abel │",
  179.  "│                     │    (D)irectory (A)rchive ... or the hexadecimal │",
  180.  "│                     │    sum of the attribute bits, where (R)=0x01    │",
  181.  "│                     │    (H)=0x02 (S)=0x04 (L)=0x08 (D)=0x10 (A)=0x20,│",
  182.  "│                     │    respectively.                                │",
  183.  "│                     │   The default format-string is:,               │",
  184.  "│                     │         \042$p\\$f$=40$s  $d $m #d, $t $y\042          │",
  185.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  186.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  187.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  188.  "│                     │ ∙  /F\042$f $p$=35#s$s #m/#d/#y #t$=67$f\042          │",
  189.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  190.  "│/G                   │ GO TO Directory (CHDIR) of matching file        │",
  191.  "│                     │   See also /Q switch.                          │",
  192.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  193.  "│/H                   │ Include switches in effect at start of listing  │",
  194.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  195.  "│/H    filename       │ Display heading lines contained in 'filename'   │",
  196.  "│                     │ at the beginning of each page of the listing.   │",
  197.  "│                     │   See also /L switch.                          │",
  198.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  199.  "│/I     # spaces      │ Indentation for each column                     │",
  200.  "│                     │   See also /C switch.                          │",
  201.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  202.  "│/L     # lines       │ Number of lines, including any user heading, to │",
  203.  "│                     │ constitute a page break.                        │",
  204.  "│                     │   See also /P switch.                          │",
  205.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  206.  "│/M     option        │ Search Multiple Drives.                         │",
  207.  "│                     │   If /M switch is not given, then only current │",
  208.  "│                     │    drive will be searched.                      │",
  209.  "│                     ├─────────────────────────────────────────────────┤",
  210.  "│         A     ¿     │ Search all drives                               │",
  211.  "│         F           │ Include all Floppy Drives                       │",
  212.  "│         J           │ Include all JOIN'ed drives                      │",
  213.  "│         H          │ Include all Hard Drives                         │",
  214.  "│         N           │ Include all Network Drives                      │",
  215.  "│         S           │ Include all SUBST'ed drives                     │",
  216.  "│                     ├─────────────────────────────────────────────────┤",
  217.  "│                     │   Sequence of search is always in ascending,   │",
  218.  "│                     │    drive letter order.                          │",
  219.  "│                     │   Any drive failures will be skipped; it is    │",
  220.  "│                     │    okay to specify the A or F option and have   │",
  221.  "│                     │    one or more diskette drives empty...LOCATE   │",
  222.  "│                     │    will exclude them.  Therefore, make sure any │",
  223.  "│                     │    floppy is ready, or it will be bypassed with │",
  224.  "│                     │    no warning or error message.                 │",
  225.  "│                     │   /MA will bypass JOIN'ed and SUBST'ed drives. │",
  226.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  227.  "│/P    [# lines]      │ Pause after every '# lines'                     │",
  228.  "│                     │   If '# lines' is not specified, then:         │",
  229.  "│                     │    ∙  If /L switch is present, its value will   │",
  230.  "│                     │       be used.                                  │",
  231.  "│                     │    ∙  If /L switch not present, 20 will be used │",
  232.  "│                     │   If output is redirected to a file or device, │",
  233.  "│                     │    or if the /H switch is specified, then this  │",
  234.  "│                     │    option is ignored                            │",
  235.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  236.  "│/Q                   │ Query (Y or N) before each BATCH attempt or GO  │",
  237.  "│                     │ TO Directory attempt                            │",
  238.  "│                     │   See also /G and /X switches.                 │",
  239.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  240.  "│/R  directory-name   │ Specify ROOT directory of operations.  LOCATE   │",
  241.  "│                     │ will then only operate in and under this ROOT.  │",
  242.  "│                     │   If /R switch is not given, the top directory │",
  243.  "│                     │    (\\) is the ROOT.                             │",
  244.  "│                     │   If directory-name is not specified, then the │",
  245.  "│                     │    current directory will be the ROOT.          │",
  246.  "│                     │   See also /E switch.                          │",
  247.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  248.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  249.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  250.  "│                     │ ∙  /R..                root is parent directory │",
  251.  "│                     │ ∙  /R\\any\\where     root is a distant directory │",
  252.  "│                     │ ∙  /Runder      root is subdirectory of current │",
  253.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  254.  "│/S    ± # bytes      │ Discriminate files by size.                     │",
  255.  "│                     │   If a positive file size is given, then only  │",
  256.  "│                     │    files that are greater than or equal to that │",
  257.  "│                     │    size will be processed.                      │",
  258.  "│                     │   If a negative file size is given, then only  │",
  259.  "│                     │    files that are smaller than that size will   │",
  260.  "│                     │    be processed.                                │",
  261.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  262.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  263.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  264.  "│                     │ ∙  /S+100000              files ≥ 100,000 bytes │",
  265.  "│                     │ ∙  /S-512                     files < 512 bytes │",
  266.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  267.  "│/S    sort-order     │ Selects sort order of each directory            │",
  268.  "│                     ├─────────────────────────────────────────────────┤",
  269.  "│         D     ¿     │ Sort by Date and Time                           │",
  270.  "│         E     ¿     │ Sort by File Extension                          │",
  271.  "│         N     ¿    │ Sort by File Name and Extension                 │",
  272.  "│         S     ¿     │ Sort by File Size                               │",
  273.  "│                     ├─────────────────────────────────────────────────┤",
  274.  "│                     │   Files can be sorted by ascending or descend- │",
  275.  "│                     │    ing order, by specifying 'sort-order' as a   │",
  276.  "│                     │    uppercase or lowercase letter, respectively. │",
  277.  "│                     │   Note: if multiple columns are selected (see  │",
  278.  "│                     │    /C switch), LOCATE will not compensate for   │",
  279.  "│                     │    the resulting disarray, and will output in   │",
  280.  "│                     │    horizontal, not vertical, progression.       │",
  281.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  282.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  283.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  284.  "│                     │ ∙  /SN                             sort by name │",
  285.  "│                     │ ∙  /Ss                  sort by decreasing size │",
  286.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  287.  "│/V    option         │ Verbosity Control                               │",
  288.  "│                     │   If /V switch is not given, no directories    │",
  289.  "│                     │    will be reported.                            │",
  290.  "│                     ├─────────────────────────────────────────────────┤",
  291.  "│        A      ¿     │ Report all directories that are visited         │",
  292.  "│        D      ¿    │ Report each directory containing reported files │",
  293.  "│        N            │ Do not include DIRS in file portion of listing  │",
  294.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  295.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  296.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  297.  "│                     │ ∙  /VA            watch where LOCATE is looking │",
  298.  "│                     │ ∙  /VDN       show each directory and its files │",
  299.  "├─────────────────────┼─────────────────────────────────────────────────┤",
  300.  "│/X  command-string   │ Batches MSDOS command for each file located     │",
  301.  "│                     │   The actual command line batched to MSDOS is  │",
  302.  "│                     │    the text in 'command-string', with the tokens│",
  303.  "│                     │    described for /F switch being replaced.      │",
  304.  "│                     │    file                                         │",
  305.  "│                     │   Token replacements are in all lowercase or   │",
  306.  "│                     │    all uppercase if the token is in lowercase   │",
  307.  "│                     │    or upper case, respectively.                 │",
  308.  "│                     │   See also /F and /Q switches.                 │",
  309.  "│                     ├┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┤",
  310.  "│                     ╞╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪ EXAMPLES ╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╪╡",
  311.  "│                     ╞╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╧╡",
  312.  "│                     │ ∙  /X\042copy $f a:\042 /Q                            │",
  313.  "│                     │ ∙  /X\042edit $f\042                                  │",
  314.  "│                     │ ∙  locate %1 /oN /x\042locate $f /ec /f\\\042$$p\\$$f$$=│",
  315.  "│                     │          40$$s  $$d $$m #d, $$t $$y\\\042\042         │",
  316.  "└─────────────────────┴─────────────────────────────────────────────────┘",
  317.  0L,
  318. };
  319. /*----------------------------------------------------------------
  320. compile and link instructions:
  321.  
  322.  tcc -mc -K -X -d- -Tt -Tmx -wrvl -wsig -wcln -wpin -wtsv
  323.      -wpro -wnod -wamb -waus -weff -wpia -wamp -wdef -wpar -wstv
  324.      -wuse -wrng locate
  325.  
  326. (COMPACT memory model must be used if directories of humongous size
  327. are to be handled)
  328. -----------------------------------------------------------------*/
  329. #include <stdio.h>
  330. #include <stdlib.h>
  331. #include <string.h>
  332. #include <io.h>
  333. #include <dir.h>
  334. #include <dos.h>
  335. #include <bios.h>
  336. #include <alloc.h>
  337. #include <conio.h>
  338. #include <ctype.h>
  339. #include <time.h>
  340.  
  341. #define OR    : case
  342.  
  343. struct subdir
  344. {
  345.     int qty;
  346.     struct ffblk *file;
  347. };
  348.  
  349. typedef int (*SORT_FUNC)(const void *obj1, const void *obj2);
  350. static SORT_FUNC sortRoutine;
  351.  
  352. static int homeDisk, recent=0, formatChanged=0, past, indent=0;
  353. static int sizeMode=0, batchMode=0, query=0, nLines=0, lineNum=999;
  354. static int beforeMode=0, afterMode=0, heading=0, headQty=0, dirs=1;
  355. static int attr=255, column=99, nColumns=1, sort=0, errorOccurred;
  356. static int verbose=0, gotoMode=0, pause=0;
  357. static int floppy=0, hard=0, network=0;
  358. static int excludeHome=0, excludeRoot=0, excludeSubs=0, excludeRootOption=0;
  359. static long lowSize, cluster;
  360. static struct tm look, days;
  361. static time_t t, today, before, after;
  362. static char *batch, *command, *homeBase, *line;
  363. static char *root = "\\";
  364. static char *template = "*.*";
  365. static char *format = "$p\\$f$=40$s  $d $m #d, $t $y";
  366. static char **headText;
  367. static char *more = "Press any key for MORE...";
  368.  
  369. #define NETWORK     (1 << 15)
  370. #define PHYSICAL    (1 << 14)
  371. #define JOIN        (1 << 13)
  372. #define SUBST       (1 << 12)
  373.  
  374. typedef struct dpb
  375. {
  376.     char drive;
  377.     char unit;
  378.     unsigned bytesPerSector;
  379.     char sectorsPerCluster;       // plus 1
  380.     char shift;                   // for sectors per cluster
  381.     unsigned bootSectors;          
  382.     char copiesFat;
  383.     unsigned maxRootDir;
  384.     unsigned firstDataSector;
  385.     unsigned highestCluster;
  386.     union
  387.     {
  388.         struct
  389.         {
  390.             unsigned char sectorsPerFat;
  391.             unsigned firstDirSector;
  392.             void far *deviceDriver;
  393.             char mediaDescriptor;
  394.             char accessFlag;
  395.             struct dpb far *next;
  396.             unsigned long reserved;
  397.         } dos3;
  398.         struct
  399.         {
  400.             unsigned sectorsPerFat;       // WORD, not BYTE!
  401.             unsigned firstDirSector;
  402.             void far *deviceDriver;
  403.             char mediaDescriptor;
  404.             char accessFlag;
  405.             struct dpb far *next;
  406.             unsigned long reserved;
  407.         } dos4;
  408.     } vers;
  409. } DPB;
  410.  
  411. typedef struct
  412. {
  413.     char currentPath[67];  // current path
  414.     unsigned flags;        // NETWORK, PHYSICAL, JOIN, SUBST
  415.     DPB far *dpb;        // pointer to Drive Parameter Block
  416.     union
  417.     {
  418.         struct
  419.         {
  420.             unsigned startCluster; // root: 0000; never accessed: FFFFh
  421.             unsigned long unknown;
  422.         } LOCAL;        // if (! (cds[drive].flags & NETWORK))
  423.         struct
  424.         {
  425.             unsigned long redirIFS;
  426.             unsigned parameter;
  427.         } NET;        // if (cds[drive].flags & NETWORK)
  428.     } u;
  429.     unsigned backslashOffset;    // offset in currentPath of '\'
  430.                     // DOS4 fields for IFS
  431.                     // 7 extra bytes...
  432. } DEVDIR;
  433.  
  434. #pragma inline
  435. DEVDIR far *currdir(unsigned drive)
  436. {
  437.     static char far *dir = NULL;
  438.     static int status = -1;
  439.     static unsigned currdirSize;
  440.     static char lastdrv;
  441.  
  442.     if (status < 0)
  443.     {
  444.         unsigned drvOfs, lastdrvOfs;
  445.  
  446.         // curr dir struct not available in DOS 1.x or 2.x
  447.         if (!(status = (_osmajor < 3) ? 0 : 1))
  448.             return(NULL);
  449.  
  450.         // compute offset of curr dir struct and LASTDRIVE in DOS
  451.             // list of lists, depending on DOS version
  452.         drvOfs = (_osmajor == 3 && _osminor == 0) ? 0x17 : 0x16;
  453.         lastdrvOfs = (_osmajor == 3 && _osminor == 0) ? 0x1b : 0x21;
  454.  
  455.         asm    push    si
  456.         asm    mov    ah,52h
  457.         asm    int    21h
  458.         asm    mov    si, lastdrvOfs
  459.         asm    mov    ah, byte ptr es:[bx+si]
  460.         asm    mov    lastdrv, ah
  461.         asm    mov    si, drvOfs
  462.         asm    les    bx, es:[bx+si]
  463.         asm    mov    word ptr dir+2, es
  464.         asm    mov    word ptr dir, bx
  465.         asm    pop    si
  466.  
  467.         if (dir == (char far *) -1L)
  468.             status = 0;
  469.  
  470.         currdirSize = (_osmajor >= 4) ? 0x58 : 0x51;
  471.  
  472.     }
  473.  
  474.     if (!status || (drive >= lastdrv))
  475.         return(NULL);
  476.  
  477.     return((DEVDIR far *)(dir + (drive * currdirSize)));
  478. }
  479.  
  480. static int query_process(char *name)
  481. {
  482.     int c;
  483.     char dir[68];
  484.  
  485.     getcwd(dir, 63);
  486.     if (strlen(dir) < 4)
  487.         dir[2] = '\0';
  488.     putchar('\n');
  489.     while (1)
  490.     {
  491.         printf("%s\\%s ? [y/n] ", dir, name);
  492.         c = getche();
  493.         putchar('\n');
  494.         c = tolower(c);
  495.         if (c == 'y' || c == 'n')
  496.             break;
  497.     }
  498.     return(c != 'n');
  499. }
  500.  
  501. static void parse_date(char *ptr, time_t *clock)
  502. {
  503.     long d;
  504.         short t;
  505.     struct tm w;
  506.  
  507.     w = *(localtime(&today));
  508.     for (t=0; isdigit(ptr[t]); ++t)
  509.     {
  510.         // do nothing
  511.     }
  512.     if (t > 4)
  513.     {
  514.         d = atol(ptr);
  515.         w.tm_year = (int)(d % 100);
  516.         w.tm_mon =  (int)(d / 10000L) - 1;
  517.         w.tm_mday = (int)((d - (long)(w.tm_mon+1)*10000L) / 100L);
  518.         ptr += t;
  519.     }
  520.     while (*ptr == ' ')
  521.         ++ptr;
  522.     for (t=0; isdigit(ptr[t]); ++t)
  523.     {
  524.         // do nothing
  525.     }
  526.     if (t)
  527.     {
  528.         t = atoi(ptr);
  529.         w.tm_hour = t / 100;
  530.         w.tm_min = t % 100;
  531.     }
  532.     else
  533.     {
  534.         w.tm_hour = 0;
  535.         w.tm_min = 0;
  536.     }
  537.     w.tm_sec = 0;
  538.     *clock = mktime(&w);
  539. }
  540.  
  541. static void create_format(char *fmtIn, char *fmtOut, struct ffblk *file)
  542. {
  543.     int copy=0, n;
  544.     char *date, *fmt;
  545.     char drive[8], dir[80], base[16], ext[8];
  546.  
  547.     fnsplit(file->ff_name, drive, dir, base, ext);
  548.     date = ctime(&t);
  549.     fmt = fmtOut;
  550.     while (*fmtIn)
  551.     {
  552.         switch (*fmtIn)
  553.         {
  554.            case '$':
  555.             switch (*(++fmtIn))
  556.             {
  557.                case 'a' OR 'A':
  558.                {
  559.                 int n, no = fmtIn[1]=='-';
  560.  
  561.                 strcpy(fmtOut, "RHSLDA");
  562.                 for (n=0; fmtOut[n]; ++n)
  563.                 {
  564.                     if (no)
  565.                     {
  566.                         if (!(file->ff_attrib&(1<<n)))
  567.                             continue;
  568.                     }
  569.                     else
  570.                     {
  571.                         if (file->ff_attrib & (1<<n))
  572.                             continue;
  573.                     }
  574.                     fmtOut[n] = 0x20;
  575.                 }
  576.                 break;
  577.                }
  578.                case 'b' OR 'B':
  579.                 sprintf(fmtOut, "%-3s", base);
  580.                 break;
  581.                case 'c' OR 'C':
  582.                 if (file->ff_attrib & 0x10)
  583.                 {
  584.                     strcpy(fmtOut, " <DIR>");
  585.                     break;
  586.                 }
  587.                 sprintf(fmtOut, "%6ld", (file->ff_fsize +
  588.                         cluster-1) / cluster);
  589.                 break;
  590.                case 'd' OR 'D':
  591.                 memcpy(fmtOut, date, 3);
  592.                 fmtOut[3] = '\0';
  593.                 break;
  594.                case 'e' OR 'E':
  595.                 sprintf(fmtOut, "%-3s", ext);
  596.                 break;
  597.                case 'f' OR 'F':
  598.                 sprintf(fmtOut, "%-12s", file->ff_name);
  599.                 break;
  600.                case 'k' OR 'K':
  601.                 if (file->ff_attrib & 0x10)
  602.                 {
  603.                     strcpy(fmtOut, "  <DIR>");
  604.                     break;
  605.                 }
  606.                 {
  607.                      ldiv_t rat = ldiv(file->ff_fsize, 1024L);
  608.                 cprintf(fmtOut, "%5ld.%1dk", rat.quot,
  609.                     (int)((rat.rem * 10L) / 1024));
  610.                 }
  611.                 break;
  612.                case 'm' OR 'M':
  613.                 memcpy(fmtOut, date+4, 3);
  614.                 fmtOut[3] = '\0';
  615.                 break;
  616.                case 'p' OR 'P':
  617.                 getcwd(fmtOut, 63);
  618.                 if (strlen(fmtOut) < 4)
  619.                     fmtOut[2] = '\0';
  620.                 break;
  621.                case 's' OR 'S':
  622.                 if (file->ff_attrib & 0x10)
  623.                 {
  624.                     strcpy(fmtOut, "   <DIR>");
  625.                     break;
  626.                 }
  627.                 sprintf(fmtOut, "%8ld", file->ff_fsize);
  628.                 break;
  629.                case 't' OR 'T':
  630.                 memcpy(fmtOut, date+11, 8);
  631.                 fmtOut[8] = '\0';
  632.                 break;
  633.                case 'y' OR 'Y':
  634.                 memcpy(fmtOut, date+20, 4);
  635.                 fmtOut[4] = '\0';
  636.                 break;
  637.                case '=':
  638.                {
  639.                      short int n;
  640.                 n = atoi(++fmtIn) - (int)(fmtOut - fmt);
  641.                 while (n-- > 0)
  642.                 {
  643.                     *fmtOut++ = ' ';
  644.                 }
  645.                 for (n=0; isdigit(fmtIn[n]); ++n)
  646.                 {
  647.                     // do nothing
  648.                 }
  649.                 fmtIn += n - (copy=1);
  650.                 break;
  651.                }
  652.                default:
  653.                        *fmtOut++ = *fmtIn;
  654.                 copy = 1;
  655.                 break;
  656.                }
  657.                break;
  658.            case '#':
  659.             switch (*(++fmtIn))
  660.             {
  661.                case 'a' OR 'A':
  662.                 sprintf(fmtOut, "0x%02x", file->ff_attrib);
  663.                 break;
  664.                case 'd' OR 'D':
  665.                 memcpy(fmtOut, date+8, 2);
  666.                 fmtOut[2] = '\0';
  667.                 break;
  668.                case 'f' OR 'F':
  669.                 getcwd(fmtOut, 63);
  670.                 if (strlen(fmtOut) < 4)
  671.                     fmtOut[2] = '\0';
  672.                 sprintf(fmtOut+strlen(fmtOut),
  673.                         "\\%-12s", file->ff_name);
  674.                 break;
  675.                case 'k' OR 'K':
  676.                 if (file->ff_attrib & 0x10)
  677.                 {
  678.                     strcpy(fmtOut, "  <DIR>");
  679.                     break;
  680.                 }
  681.                 {
  682.                      ldiv_t rat = ldiv(((file->ff_fsize +
  683.                         cluster-1) / cluster) *
  684.                         cluster, 1024L);
  685.                 sprintf(fmtOut, "%5ld.%1dk", rat.quot,
  686.                     (int)((rat.rem * 10L) / 1024));
  687.                 }
  688.                 break;
  689.                case 'm' OR 'M':
  690.                 sprintf(fmtOut, "%02d", look.tm_mon);
  691.                 break;
  692.                case 'p' OR 'P':
  693.                 getcwd(fmtOut, 63);
  694.                 for (n=strlen(fmtOut); n>-1; n--)
  695.                 {
  696.                     if (fmtOut[n]=='\\'||fmtOut[n]=='/')
  697.                         break;
  698.                 }
  699.                 memcpy(fmtOut+n, fmtOut, n);
  700.                 break;
  701.                case 's' OR 'S':
  702.                 if (file->ff_attrib & 0x10)
  703.                 {
  704.                     strcpy(fmtOut, "   <DIR>");
  705.                     break;
  706.                 }
  707.                 sprintf(fmtOut, "%8ld", ((file->ff_fsize +
  708.                         cluster-1) / cluster) *
  709.                         cluster);
  710.                 break;
  711.                case 't' OR 'T':
  712.                 memcpy(fmtOut, date+11, 5);
  713.                 fmtOut[5] = '\0';
  714.                 break;
  715.                case 'u' OR 'U':
  716.                {
  717.                    char work[80];
  718.  
  719.                 getcwd(work, 70);
  720.                    for (n=strlen(work); n>-1; --n)
  721.                 {
  722.                     if (work[n]=='\\' || work[n]=='/')
  723.                         break;
  724.                 }
  725.                 strcpy(fmtOut, work+n);
  726.                 break;
  727.                }
  728.                case 'y' OR 'Y':
  729.                 memcpy(fmtOut, date+22, 2);
  730.                 fmtOut[2] = '\0';
  731.                 break;
  732.                default:
  733.                        *fmtOut++ = *fmtIn;
  734.                 copy = 1;
  735.                 break;
  736.             }
  737.             break;
  738.            default:
  739.                    *fmtOut++ = *fmtIn;
  740.             copy = 1;
  741.             break;
  742.         }
  743.         if (!copy)
  744.         {
  745.             if (isupper(*fmtIn))
  746.                 strupr(fmtOut);
  747.             else
  748.                 strlwr(fmtOut);
  749.             fmtOut += strlen(fmtOut);
  750.         }
  751.         else
  752.         {
  753.             copy = 0;
  754.         }
  755.         ++fmtIn;
  756.     }
  757.     *fmtOut = '\0';
  758. }
  759.  
  760. static int sort_by_date(struct ffblk *file1, struct ffblk *file2)
  761. {
  762.     if (file1->ff_fdate == file2->ff_fdate)
  763.         return((int)(file1->ff_ftime - file2->ff_ftime) * sort);
  764.     return((int)(file1->ff_fdate - file2->ff_fdate) * sort);
  765. }
  766.  
  767. static int sort_by_ext(struct ffblk *file1, struct ffblk *file2)
  768. {
  769.     char drive[8], dir[80], base[16], ext1[8], ext2[8];
  770.     fnsplit(file1->ff_name, drive, dir, base, ext1);
  771.     fnsplit(file2->ff_name, drive, dir, base, ext2);
  772.     return(strcmp(ext1, ext2) * sort);
  773. }
  774.  
  775. static int sort_by_name(struct ffblk *file1, struct ffblk *file2)
  776. {
  777.     return(strcmp(file1->ff_name, file2->ff_name) * sort);
  778. }
  779.  
  780. static int sort_by_size(struct ffblk *file1, struct ffblk *file2)
  781. {
  782.     return((int)(file1->ff_fsize - file2->ff_fsize) * sort);
  783. }
  784.  
  785. static void get_heading(char *fileName)
  786.          FILE *file;
  787.   
  788.       if (!(file=fopen(fileName, "rt")))
  789.     {
  790.           printf("Could not open heading file %s\n", fileName);
  791.           exit(7);
  792.     }
  793.     // first, find out how many lines there are
  794.     while (fgets(line, 511, file))
  795.         ++headQty;
  796.     rewind(file);
  797.     headText = (char **)malloc(headQty * sizeof(char*));
  798.     headQty = 0;
  799.     while (fgets(line, 511, file))
  800.         headText[headQty++] = strdup(line);
  801.     fclose(file);
  802. }
  803.  
  804. static void check_abort(void)
  805. {
  806.     int c;
  807.  
  808.     if (!kbhit())
  809.         return;
  810.     while (kbhit())
  811.         c = getch();
  812.     printf("\nPaused...ESC=end...any other key=continue");
  813.     c = getch();
  814.     printf("\r                                         \r");
  815.     if (c != 0x1b)
  816.         return;
  817.     setdisk(homeDisk);
  818.     chdir(homeBase);
  819.     exit(9);
  820. }
  821.  
  822. static void check_page_break(void)
  823. {
  824.     int n;
  825.  
  826.     if (++column >= nColumns)
  827.     {
  828.         putchar('\n');
  829.         column = 0;
  830.          if (nLines && (++lineNum > nLines))
  831.         {
  832.             putchar('\f');
  833.             for (lineNum=0; lineNum<headQty; ++lineNum)
  834.                 printf("%s", headText[lineNum]);
  835.         }
  836.         else
  837.         {
  838.             if (pause && (++lineNum > pause))
  839.             {
  840.                 printf(more);
  841.                  if (getch()==0x1b)
  842.                     exit(3);
  843.                 putchar('\r');
  844.                 lineNum = 0;
  845.             }
  846.         }
  847.     }
  848.     for (n=0; n<indent; ++n)
  849.         putchar(' ');
  850. }
  851.  
  852. static int directory(char *template, int att, struct subdir *info)
  853. {
  854.     struct
  855.     {
  856.         struct ffblk dir;
  857.         char safety[128];
  858.     } data;
  859.  
  860.     int qty=0, status = findfirst(template, &data.dir, 0xff);
  861.  
  862.     while (!status)
  863.     {
  864.         if (data.dir.ff_name[0] != '.' && ((att==0xff) ||
  865.                 (data.dir.ff_attrib & att)))
  866.         {
  867.               ++qty;
  868.         }
  869.         status = findnext(&data.dir);
  870.     }
  871.     if (!(info->qty=qty))
  872.         return(0);
  873.     info->file = (struct ffblk *)malloc(sizeof(struct ffblk) * qty);
  874.     qty = 0;
  875.     status = findfirst(template, &data.dir, 0xff);
  876.     while (!status)
  877.     {
  878.         if (data.dir.ff_name[0] != '.' && ((att==0xff) ||
  879.                 (data.dir.ff_attrib & att)))
  880.         {
  881.               info->file[qty++] = data.dir;
  882.         }
  883.         status = findnext(&data.dir);
  884.     }
  885.     if (sort)
  886.     {
  887.         qsort(info->file,info->qty,sizeof(struct ffblk),sortRoutine);
  888.     }
  889.     return(info->qty);
  890. }
  891.  
  892. static void process_file(struct ffblk *file)
  893. {                    
  894.     if (!dirs && (file->ff_attrib & 0x10))
  895.         return;
  896.     switch (sizeMode)
  897.     {
  898.        case 1:
  899.         if (file->ff_fsize < lowSize)
  900.             return;
  901.         break;
  902.        case 2:
  903.          if (file->ff_fsize >= lowSize)
  904.             return;
  905.         break;
  906.     }
  907.     look.tm_year = 80 + ((file->ff_fdate >> 9) & 0x7f);
  908.     look.tm_mon = ((file->ff_fdate >> 5) & 0x0f) - 1;
  909.     look.tm_mday = file->ff_fdate & 0x1f;
  910.     look.tm_hour = (file->ff_ftime >> 11) & 0x1f;
  911.     look.tm_min = (file->ff_ftime >> 5) & 0x3f;
  912.     look.tm_sec = (file->ff_ftime & 0x1f) * 2;
  913.     t = mktime(&look);
  914.     if (recent && (t < after))
  915.         return;
  916.     if (afterMode && (t < after))
  917.         return;
  918.     if (beforeMode && (t > before))
  919.         return;
  920.     if ((verbose==2) && (column>98))
  921.     {
  922.         check_page_break();
  923.         getcwd(line, 63);
  924.         printf("Directory %s", line);
  925.         column=99;
  926.     }
  927.     check_page_break();
  928.     create_format(format, line, file);
  929.     printf("%s", line);
  930.     if (gotoMode)
  931.     {
  932.         if (!query || query_process(file->ff_name))
  933.             exit(5);
  934.     }
  935.     if (batchMode)
  936.     {
  937.         char dir[70];
  938.  
  939.         if (query && !query_process(file->ff_name))
  940.             return;
  941.         check_page_break();
  942.         create_format(batch, command, file);
  943.         getcwd(dir, 68);
  944.         system(command);
  945.         chdir(dir);
  946.     }
  947. }
  948.  
  949. static void search_drive(int level)
  950. {
  951.     int qty;
  952.     char *home;
  953.     struct subdir dir;
  954.     struct ffblk *file;
  955.  
  956.     getcwd(line, 63);
  957.     if (!excludeRoot && !(excludeHome && !strcmp(homeBase, line)))
  958.     {
  959.         if (verbose==1)
  960.         {
  961.             check_page_break();
  962.             printf("Directory %s\n", line);
  963.         }
  964.         qty = directory(template, attr, &dir);
  965.         for (file = dir.file; dir.qty--; ++file)
  966.         {
  967.             check_abort();
  968.             process_file(file);
  969.         }
  970.         column = 99;
  971.         if (qty)
  972.             free(dir.file);
  973.     }
  974.     excludeRoot = 0;
  975.     if (!excludeSubs)
  976.     {
  977.         if (directory("*.*", 0x10, &dir))
  978.         {
  979.             home = malloc(64);
  980.             for (file = dir.file; dir.qty--; ++file)
  981.             {
  982.                 check_abort();
  983.                 getcwd(home, 63);
  984.                 if (chdir(file->ff_name))
  985.                     continue;
  986.                 search_drive(level+1);
  987.                 chdir(home);
  988.             }
  989.             free(home);
  990.             free(dir.file);
  991.         }
  992.     }
  993.     if (level == 1)
  994.         chdir(homeBase);
  995. }
  996.  
  997. static int error_handler(void)
  998. {
  999.     errorOccurred = 1;
  1000.     hardretn(0);
  1001.     hardresume(0);
  1002.     return(0);
  1003. }
  1004.  
  1005. void process_drive(int drive)
  1006. {
  1007.     static struct fatinfo fat;
  1008.  
  1009.     errorOccurred = 0;
  1010.     setdisk(drive);
  1011.     if (errorOccurred)
  1012.         return;
  1013.     getfat(drive+1, &fat);
  1014.     getcwd(homeBase, 63);
  1015.     cluster = (long)((int)fat.fi_sclus * fat.fi_bysec);
  1016.     chdir(root);
  1017.     lineNum = (pause && !nLines) ? 0 : 999;
  1018.     column = 99;
  1019.     excludeRoot = excludeRootOption;
  1020.     search_drive(1);
  1021. }
  1022.  
  1023. static void help(int argc, char **argv)
  1024. {
  1025.     int n, s=-1, x, qty, inHelp;
  1026.     char helpWanted[26];
  1027.     char *bottom;
  1028.  
  1029.     memset(helpWanted, 0, qty=sizeof(helpWanted));
  1030.      for (n = 1; n < argc; ++n)
  1031.     {
  1032.         if (argv[n][0] != '/')
  1033.             continue;
  1034.         x = toupper(argv[n][1])-'A';
  1035.         if (x > -1 && x < 26)
  1036.         {
  1037.             helpWanted[x] = 1;
  1038.             if (s < 0)
  1039.                 s = x;
  1040.         }
  1041.     }
  1042.     argv = description;
  1043.     n = 0;
  1044.     if (s > -1)
  1045.     {
  1046.         while (*argv)
  1047.         {
  1048.             if (argv[0][0] == 192)
  1049.             {
  1050.                 bottom = *argv;
  1051.                 break;
  1052.             }
  1053.             ++argv;
  1054.         }
  1055.         argv = description;
  1056.         for (n=0; *argv; ++argv, ++n)
  1057.         {
  1058.             puts(*argv);
  1059.             if (argv[0][0] == 195)
  1060.                 break;
  1061.         }
  1062.     }
  1063.     for (inHelp=0; *argv; ++argv)
  1064.     {
  1065.          if (s < 0)
  1066.             puts(*argv);
  1067.         else
  1068.         {
  1069.             if (!inHelp && argv[0][1] != '/')
  1070.                 continue;
  1071.             if (!inHelp && (argv[0][2]-'A') != s)
  1072.                 continue;
  1073.             if (inHelp && argv[0][1]=='/' && (argv[0][2]-'A')!=s)
  1074.             {
  1075.                 inHelp = 0;
  1076.                 while (++s < qty)
  1077.                 {
  1078.                     if (helpWanted[s])
  1079.                         break;
  1080.                 }
  1081.                 if (s >= qty)
  1082.                 {
  1083.                     puts(bottom);
  1084.                     return;
  1085.                 }
  1086.                 --argv;
  1087.                 continue;
  1088.             }
  1089.             if (!inHelp)
  1090.             {
  1091.                 inHelp = 1;
  1092.             }
  1093.             puts(*argv);
  1094.         }
  1095.         if (stdout->flags & _F_TERM)
  1096.         {
  1097.             if (++n > 18)
  1098.             {
  1099.                 printf(more);
  1100.                  if (getch()==0x1b)
  1101.                     exit(3);
  1102.                 putchar('\r');
  1103.                 n = 0;
  1104.             }
  1105.         }
  1106.     }
  1107. }
  1108.  
  1109. int main(int argc, char **argv)
  1110. {
  1111.     int n, attrSet, drive, lastDrive;
  1112.     char *arg, *sw;
  1113.     unsigned char far *floppyFlag = (unsigned char far *)0x504L;
  1114.  
  1115.      line = malloc(1024);
  1116.      today = time(NULL);
  1117.      for (n = 1; n < argc; ++n)
  1118.     {
  1119.         sw = argv[n];
  1120.         switch (sw[0])
  1121.         {
  1122.            case '/':
  1123.             arg = sw+2;
  1124.             switch (sw[1])
  1125.             {
  1126.                case 'a' OR 'A':
  1127.                 if (!*arg && (argv[n+1][0] != '/'))
  1128.                 {
  1129.                     arg = argv[++n];
  1130.                 }
  1131.                 if (isdigit(*arg))
  1132.                 {
  1133.                     afterMode = 1;
  1134.                     parse_date(arg, &after);
  1135.                     break;
  1136.                 }
  1137.                 attr = 0;
  1138.                 while (*arg)
  1139.                 {
  1140.                     switch (*arg++)
  1141.                     {
  1142.                        case 'r' OR 'R':
  1143.                         attrSet = FA_RDONLY;
  1144.                         break;
  1145.                        case 'h' OR 'H':
  1146.                         attrSet = FA_HIDDEN;
  1147.                         break;
  1148.                        case 's' OR 'S':
  1149.                         attrSet = FA_SYSTEM;
  1150.                         break;
  1151.                        case 'l' OR 'L':
  1152.                         attrSet = FA_LABEL;
  1153.                         break;
  1154.                        case 'd' OR 'D':
  1155.                         attrSet = FA_DIREC;
  1156.                         break;
  1157.                        case 'a' OR 'A':
  1158.                         attrSet = FA_ARCH;
  1159.                         break;
  1160.                     }
  1161.                     if (*arg == '-')
  1162.                     {
  1163.                         attr = attr & (~attrSet);
  1164.                         ++arg;
  1165.                     }
  1166.                     else
  1167.                     {
  1168.                         attr |= attrSet;
  1169.                     }
  1170.                 }
  1171.                 break;
  1172.                case 'b' OR 'B':
  1173.                 if (!*arg && (argv[n+1][0] != '/'))
  1174.                 {
  1175.                     arg = argv[++n];
  1176.                 }
  1177.                 beforeMode = 1;
  1178.                 parse_date(arg, &before);
  1179.                 break;
  1180.                case 'c' OR 'C':
  1181.                 nColumns = atoi(arg);
  1182.                 break;
  1183.                case 'd' OR 'D':
  1184.                 recent = 1;
  1185.                 days = *localtime(&today);
  1186.                 if ((past = atoi(arg)) < 1)
  1187.                     past = 1;
  1188.                 days.tm_mday -= (past-1);
  1189.                 days.tm_hour = 0;
  1190.                 days.tm_min = 0;
  1191.                 days.tm_sec = 0;
  1192.                  after = mktime(&days);
  1193.                 break;
  1194.                case 'e' OR 'E':
  1195.                 if (!*arg)
  1196.                 {
  1197.                     excludeHome = 1;
  1198.                     break;
  1199.                 }
  1200.                 while (*arg)
  1201.                 {
  1202.                     switch (*arg++)
  1203.                     {
  1204.                        case 'r' OR 'R':
  1205.                         excludeRootOption = 1;
  1206.                         break;
  1207.                        case 's' OR 'S':
  1208.                         excludeSubs = 1;
  1209.                         break;
  1210.                        case 'c' OR 'C':
  1211.                         excludeHome = 1;
  1212.                         break;
  1213.                     }
  1214.                 }
  1215.                 break;
  1216.                case 'f' OR 'F':
  1217.                 if (!*arg && (argv[n+1][0] != '/'))
  1218.                 {
  1219.                     arg = argv[++n];
  1220.                 }
  1221.                 formatChanged = 1;
  1222.                 format = malloc(256);
  1223.                 strcpy(format, arg);
  1224.                 break;
  1225.                case 'g' OR 'G':
  1226.                 gotoMode = 1;
  1227.                 break;
  1228.                case 'h' OR 'H':
  1229.                 heading = 1;
  1230.                 if (*arg)
  1231.                     get_heading(arg);
  1232.                 break;
  1233.                case 'i' OR 'I':
  1234.                 indent = atoi(arg);
  1235.                 break;
  1236.                case 'l' OR 'L':
  1237.                 nLines = atoi(arg);
  1238.                 break;
  1239.                case 'm' OR 'M':
  1240.                {
  1241.                 hard = 1;
  1242.                 while (*arg)
  1243.                 {
  1244.                     switch (*arg++)
  1245.                     {
  1246.                        case 'f' OR 'F':
  1247.                         floppy = 1;
  1248.                         break;
  1249.                        case 'n' OR 'N':
  1250.                         network = 1;
  1251.                         break;
  1252.                        case 'a' OR 'A':
  1253.                         floppy = 1;
  1254.                         network = 1;
  1255.                         break;
  1256.                     }
  1257.                 }
  1258.                 break;
  1259.                }
  1260.                case 'p' OR 'P':
  1261.                 if (!(stdout->flags & _F_TERM))
  1262.                     break;
  1263.                 if (*arg)
  1264.                     pause = atoi(arg);
  1265.                 else
  1266.                     pause = -1;
  1267.                 break;
  1268.                case 'q' OR 'Q':
  1269.                 query = 1;
  1270.                 break;
  1271.                case 'r' OR 'R':
  1272.                 if (!*arg)
  1273.                     arg = ".";
  1274.                 root = arg;
  1275.                 break;
  1276.                case 's' OR 'S':
  1277.                 switch (*arg)
  1278.                 {
  1279.                    case '+' OR '-':
  1280.                     sizeMode = 1;
  1281.                     if ((lowSize = atol(arg))<1)
  1282.                     {
  1283.                         sizeMode = 2;
  1284.                         lowSize = labs(lowSize);
  1285.                     }
  1286.                     break;
  1287.                    case 'd' OR 'D':
  1288.                     sortRoutine = (SORT_FUNC)sort_by_date;
  1289.                     break;
  1290.                    case 'e' OR 'E':
  1291.                     sortRoutine = (SORT_FUNC)sort_by_ext;
  1292.                     break;
  1293.                    case 'n' OR 'N':
  1294.                     sortRoutine = (SORT_FUNC)sort_by_name;
  1295.                     break;
  1296.                    case 's' OR 'S':
  1297.                     sortRoutine = (SORT_FUNC)sort_by_size;
  1298.                     break;
  1299.                    default:
  1300.                     printf("Invalid /S option:  %s\n",
  1301.                                 arg);
  1302.                     puts("Use /? for help");
  1303.                     exit(1);
  1304.                 }
  1305.                 if ((*arg != '+') && (*arg != '-'))
  1306.                     sort = isupper(*arg) ? 1 : -1;
  1307.                 break;
  1308.                case 'v' OR 'V':
  1309.                 if (!*arg)
  1310.                 {
  1311.                     verbose = 2;
  1312.                     break;
  1313.                 }
  1314.                 while (*arg)
  1315.                 {
  1316.                     switch (*arg++)
  1317.                     {
  1318.                        case 'a' OR 'A':
  1319.                         verbose = 1;
  1320.                         break;
  1321.                        case 'd' OR 'D':
  1322.                         verbose = 2;
  1323.                         break;
  1324.                        case 'n' OR 'N':
  1325.                         dirs = 0;
  1326.                         break;
  1327.                     }
  1328.                 }
  1329.                 break;
  1330.                case 'x' OR 'X':
  1331.                 if (!*arg && (argv[n+1][0] != '/'))
  1332.                 {
  1333.                     arg = argv[++n];
  1334.                 }
  1335.                 batchMode = 1;
  1336.                 batch = malloc(256);
  1337.                 command = batch + 128;
  1338.                 strcpy(batch, arg);
  1339.                 break;
  1340.                case '?':
  1341.                    help(argc, argv);
  1342.                  exit(2);
  1343.                default:
  1344.                 printf("Invalid option:  %s\n", sw);
  1345.                 puts("Use /? for help");
  1346.                 exit(1);
  1347.             }
  1348.             break;
  1349.            default:
  1350.             template = sw;
  1351.             break;
  1352.         }
  1353.     }
  1354.     if (pause < 0)
  1355.         pause = nLines ? nLines : 20;
  1356.     if (!headQty)
  1357.         nLines = 0;
  1358.     if (heading && !headQty)
  1359.     {
  1360.         if (afterMode)
  1361.             printf("/A: Files after %s", ctime(&after));
  1362.         if (beforeMode)
  1363.             printf("/B: Files before %s", ctime(&before));
  1364.         if (nColumns > 1)
  1365.             printf("/C: List %d columns\n", nColumns);
  1366.         if (recent)
  1367.             printf("/D: Files %d days old\n", past);
  1368.         if (formatChanged)
  1369.             printf("/F: Format: %s\n", format);
  1370.         if (nLines)
  1371.             printf("/L: %s lines per page\n", nLines);
  1372.         if (strcmp(root, "\\"))
  1373.             printf("/R: Root Directory is %s\n", root);
  1374.         switch (sizeMode)
  1375.         {
  1376.            case 1:
  1377.             printf("/S: Files at least %ld bytes in size\n",
  1378.                     lowSize);
  1379.             break;
  1380.            case 2:
  1381.             printf("/S: Files less than %ld bytes in size\n",
  1382.                     lowSize);
  1383.             break;
  1384.         }
  1385.         if (attr != 0xff)
  1386.             printf("/A: Attributes: 0x%02x\n", attr);
  1387.         if (batchMode)
  1388.             printf("/X: Batch specified is: %s\n", batch);
  1389.     }
  1390.     harderr(error_handler);
  1391.     homeBase = malloc(64);
  1392.     lastDrive = setdisk(homeDisk=getdisk());
  1393.         for (drive=0; drive<lastDrive; ++drive)
  1394.     {
  1395.         int status;
  1396.         DEVDIR far *dir;
  1397.  
  1398.         if (drive == homeDisk)
  1399.         {
  1400.             process_drive(drive);
  1401.             continue;
  1402.         }
  1403.         if ((drive>1 && !hard))
  1404.             continue;
  1405.         if (drive<2 && !floppy)
  1406.             continue;
  1407.         if (drive > 1)
  1408.         {
  1409.             if (((dir = currdir(drive)) != NULL) &&
  1410.                     dir->flags && !(dir->flags & JOIN) &&
  1411.                     !(dir->flags & SUBST) &&
  1412.                     !((dir->flags & NETWORK) && !network))
  1413.                 process_drive(drive);
  1414.             continue;
  1415.         }
  1416.         status = biosdisk(4, drive, 0, 0, 1, 1, line);
  1417.         if (!status || status==0x06)
  1418.             process_drive(drive);
  1419.     }
  1420.     setdisk(homeDisk);
  1421.     chdir(homeBase);
  1422.     return(0);
  1423. }
  1424.